package com.whf.android.jar.net.rx.t;

import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.whf.android.jar.app.ConfigKeys;
import com.whf.android.jar.app.Latte;
import com.whf.android.jar.tool.Observer;
import com.whf.android.jar.util.log.LatteLogger;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Class description：Encapsulates an abstract base class for retrofit integrated 0kHttp3
 *
 * @author wang.hai.fang
 * @since 2.5.0
 */
abstract class BaseRxRetrofit {


    private static Retrofit mRetrofit;
    private static OkHttpClient mOkHttpClient;


    /**
     * Getting Retrofit objects
     *
     * @return Retrofit
     */
    @Nullable
    protected Retrofit getRetrofit() {
        if (null == mRetrofit) {
            if (null == mOkHttpClient) {
                if (isBaseUrl()) {
                    mOkHttpClient = RetrofitUrlManager
                            .getInstance()
                            .with(getOkHttpClient())
                            .build();
                } else {
                    mOkHttpClient = OKHttpHolder.OK_HTTP_CLIENT;
                }
            }
            final String baseUrl = Latte.getServer();
            LatteLogger.i(baseUrl);
            if (TextUtils.isEmpty(baseUrl)) {
                return null;
            }
            mRetrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(mOkHttpClient)
                    .build();
        }
        return mRetrofit;
    }

    /**
     * 是否需要替换 BaseUrl
     */
    protected boolean isBaseUrl() {
        return true;
    }


    /**
     * Insert observer
     *
     * @param observable:Observable
     * @param observer:Observer
     * @param <T>                   :  T
     */
    protected static <T> void setSubscribe(@NonNull Observable<T> observable, Observer<T> observer) {
        observable.subscribeOn(Schedulers.io())
                //Zi Xian cheng visits the network
                .subscribeOn(Schedulers.newThread())
                //Callback to main thread
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     * okHttp拦截器
     */
    protected ArrayList<Interceptor> interceptors() {
        return Latte.getConfiguration(ConfigKeys.INTERCEPTOR);
    }

    @NonNull
    protected OkHttpClient.Builder getOkHttpClient() {
        final OkHttpClient.Builder builder = new OkHttpClient
                .Builder()
                .addInterceptor(new Interceptor() {

                    @NotNull
                    @Override
                    public Response intercept(@NonNull Chain chain) throws IOException {
                        Request.Builder builder = chain.request().newBuilder();
                        builder.addHeader("Content-Type", "application/x-www-form-urlencoded");
                        builder.addHeader("Content-Type", "application/json");
                        return chain.proceed(builder.build());
                    }
                })

                // 整个网络最多使用时间 (当你的应用内需要限定 App 在某个指定的时间内得到响应结果，如果在指定时间内未能得到就认为是超时的话)。
                .callTimeout(Latte.getTimeOutCall(), TimeUnit.MINUTES)

                // 连接网络（如果 Retrofit 在指定的时间内无法与服务器端建立连接，那么 Retrofit 就认为这次请求失败）
                .connectTimeout(Latte.getTimeOut(), TimeUnit.MINUTES)

                // 写入超时(注意这个并不是说在指定的时间（比如 15 秒）内需要把所有的数据都发送到服务器端，而是指相邻的两个字节之间的发送时间不能超过指定的时间（15 秒）。
                .writeTimeout(15, TimeUnit.SECONDS)

                // 读取超时(注意这个并不是说在指定的时间（比如 30 秒）内需要把响应内容完全接收，而是指相邻的两个字节之间的接收时间不能超过指定的时间（ 30 秒）)
                .readTimeout(30, TimeUnit.SECONDS);

        final ArrayList<Interceptor> INTERCEPTORS = interceptors();
        if (INTERCEPTORS != null && !INTERCEPTORS.isEmpty()) {
            for (Interceptor interceptor : INTERCEPTORS) {
                builder.addInterceptor(interceptor);
            }
        }

        return builder;
    }

    /**
     * 构建OkHttp
     */
    private static final class OKHttpHolder {
        private static final OkHttpClient.Builder BUILDER = new OkHttpClient.Builder();
        private static final ArrayList<Interceptor> INTERCEPTORS = Latte.getConfiguration(ConfigKeys.INTERCEPTOR);

        private static OkHttpClient.Builder addInterceptor() {
            if (INTERCEPTORS != null && !INTERCEPTORS.isEmpty()) {
                for (Interceptor interceptor : INTERCEPTORS) {
                    BUILDER.addInterceptor(interceptor);
                }
            }

            return BUILDER;
        }

        private static final OkHttpClient OK_HTTP_CLIENT = addInterceptor()
                // 整个网络最多使用时间 (当你的应用内需要限定 App 在某个指定的时间内得到响应结果，如果在指定时间内未能得到就认为是超时的话)。
                .callTimeout(Latte.getTimeOutCall(), TimeUnit.MINUTES)

                // 连接网络（如果 Retrofit 在指定的时间内无法与服务器端建立连接，那么 Retrofit 就认为这次请求失败）
                .connectTimeout(Latte.getTimeOut(), TimeUnit.MINUTES)

                // 写入超时(注意这个并不是说在指定的时间（比如 15 秒）内需要把所有的数据都发送到服务器端，而是指相邻的两个字节之间的发送时间不能超过指定的时间（15 秒）。
                .writeTimeout(15, TimeUnit.SECONDS)

                // 读取超时(注意这个并不是说在指定的时间（比如 30 秒）内需要把响应内容完全接收，而是指相邻的两个字节之间的接收时间不能超过指定的时间（ 30 秒）)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();
    }

}